local nl = require"luaNumeric"
local plot = require "Q2DViewerEx"
local unity = require "luaUnity"

-----------------------------------------------------------------------------
--初始化参数
local FarfieldsPostProcessing={
     nheader = 7;
     data = {}; -- file to table
     thetas = {};
     phis = {};
     freqs = {};
     
};
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--创建表和创建元表
function FarfieldsPostProcessing:new (o)
	o = o or {};
	self.__index = self;	
	setmetatable(o,self)
	-- print( "RCSPost new" )
	o.data = nl.new_eigen_ctensor4(1,1,1,1);
	return o;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--与GUI交换数据
function FarfieldsPostProcessing:update_list_from_ui()
end
function FarfieldsPostProcessing:update_selections_to_ui()
end
function FarfieldsPostProcessing:update_list_to_ui()
end
-----------------------------------------------------------------------------

function Set(list)
	local set1 = {}
	for _,v in pairs(list) do set1[tostring(v)] = true; end
	
	local set2 = {}
	for k,v in pairs(set1) do table.insert( set2, k ); end
	return set2;
end
function ReIndexSet(set1)
	local set2 = {}
	for k,v in pairs(set1) do set2[v]=k; end
	return set2;
end

--================================================================--
--读取Gallop模型里面Farfield数据
function FarfieldsPostProcessing:read_from_model()				 

	local  farboxs = Geometry.farbox_list(); 
	assert( #farboxs>0, '模型里不含有近远场变换盒子')
	
	local data = farboxs[1]:results_tensor3()
	assert( #data.theta>0, '近远场盒子数据为空' ) 
	self.freq = data.freq;
	local theta = data.theta;
	local phi = data.phi;
	local tensor3 = data.data;

	--频率维度直接转换为字符串数组，无需压缩
	self.freq_str_idx = {};
	for k,v in pairs(self.freq) do 
		self.freq_str_idx[k] = tostring(v);
	end
	
	--theta和phi的维度索引需要压缩
   	self.theta_str_idx = Set (theta );
	self.phi_str_idx = Set (phi );
	table.sort(self.theta_str_idx,function (a,b) return tonumber(a)<tonumber(b) end )
	table.sort(self.phi_str_idx,function (a,b) return tonumber(a)<tonumber(b) end )
	self.fields_type_idx={'Etheta','EPhi'}
	
	self.theta_reidx = ReIndexSet(self.theta_str_idx);
	self.phi_reidx = ReIndexSet(self.phi_str_idx);
	self.freq_reidx = ReIndexSet(self.freq_str_idx);
	self.fields_type_reidx = ReIndexSet(self.fields_type_idx);
	
	self.theta = nl.new_vector();
	self.theta:reserve( #self.theta_str_idx )
	for k,v in pairs(self.theta_str_idx) do 
		self.theta:add( tonumber(v) );
	end
	
	self.phi = nl.new_vector();
	self.phi:reserve( #self.phi_str_idx )
	for k,v in pairs(self.phi_str_idx) do 
		self.phi:add( tonumber(v) );
	end
	
	
	--tensor3转化为tensor4
	--tensor3的维度为：theta, freq,
	--把tensor3的数据维度转换为tensor4
	local tensor4 = nl.new_eigen_ctensor4(#self.theta_str_idx,#self.phi_str_idx,#self.freq_str_idx,2);
	local listdata = {}
	for kt,vt in pairs(self.theta_str_idx) do
		for kp,vp in pairs(self.theta_str_idx) do
			label = vt..vp;
			listdata[label] = {kt,kp};
		end
	end
	
	for ii=1,#theta do 
		local label = tostring(theta[ii])..tostring(phi[ii]);
		local idx = listdata[label];
		assert( idx~=nil, '数据不完整')
		for kk=1,#self.freq_str_idx do 
			tensor4[{idx[1],idx[2],kk,1}] = tensor3[ {idx[1],kk,1}]
			tensor4[{idx[1],idx[2],kk,2}] = tensor3[ {idx[1],kk,2}]
		end 		
	end
	self.data = tensor4;
	self:update_list_to_ui()
end
--================================================================--

--===========================================================================--
--点击添加曲线按钮的响应函数
function FarfieldsPostProcessing:add_curves()
	post_funcs = {}
	post_funcs[1] = function( theta,phi)
		return nl.sqrt(nl.abs(theta)*nl.abs(theta)+nl.abs(phi)*nl.abs(phi));
	end
	post_funcs[2] = function( theta,phi)
		return nl.abs(theta);
	end
	post_funcs[3] = function( theta,phi)
		return nl.abs(phi);
	end
	local fts,thetas,phis,freqs,xAxis = self:update_selections_index_from_ui()
	self.view = Gallop.View:create_view2D();
	self:init_view(xAxis);
	for kp,vp in pairs(phis) do 
		for kf,vf in pairs(freqs) do 
			local theta = self.theta;
			local etheta = self.data:chip(self.theta_idx, vp+1,vf+1,1 );
			local ephi = self.data:chip(self.theta_idx, vp+1,vf+1,2 );
			for kft,vft in pairs( fts ) do 
				self.view:addGraph(theta,post_funcs[vft+1](etheta,ephi),
						self.fields_type_idx[vft+1] 
						..' @ φ ['..self.theta_str_idx[vp+1]..'°]'
						..', Freq ['..self.freq_str_idx[vf+1]..Geometry.ref_units_freq_str() .. ']'
						)
			end
		end
	end
	
	self.view:rescaleAxes();
end
--===========================================================================--

--===========================================================================--
--点击添加曲线按钮的响应函数
function FarfieldsPostProcessing:init_view(xAxis)
	if xAxis==0 then
		Gallop.View:init_2dplot( '方位角[°]', 'Eth' ) 
	end
end
--===========================================================================--

--===========================================================================--
--读取Gallop模型里面Farfield数据
function FarfieldsPostProcessing:read_from_model()				 

	local  farboxs = Geometry.farbox_list(); 
	assert( #farboxs>0, '模型里不含有近远场变换盒子')
	
	local data = farboxs[1]:results_tensor3()
	assert( #data.theta>0, '近远场盒子数据为空' ) 
	self.freq = data.freq;
	local theta = data.theta;
	local phi = data.phi;
	local tensor3 = data.data;

	--频率维度直接转换为字符串数组，无需压缩
	self.freq_str_idx = {};
	for k,v in pairs(self.freq) do 
		self.freq_str_idx[k] = tostring(v);
	end
	
	--theta和phi的维度索引需要压缩
   	self.theta_str_idx = Set (theta );
	self.phi_str_idx = Set (phi );
	table.sort(self.theta_str_idx,function (a,b) return tonumber(a)<tonumber(b) end )
	table.sort(self.phi_str_idx,function (a,b) return tonumber(a)<tonumber(b) end )
	self.fields_type_idx={'ETotal','Etheta','EPhi'}
	
	self.theta_reidx = ReIndexSet(self.theta_str_idx);
	self.phi_reidx = ReIndexSet(self.phi_str_idx);
	self.freq_reidx = ReIndexSet(self.freq_str_idx);
	self.fields_type_reidx = ReIndexSet(self.fields_type_idx);
	
	self.theta = nl.new_vector();
	self.theta:reserve( #self.theta_str_idx )
	for k,v in pairs(self.theta_str_idx) do 
		self.theta:add( tonumber(v) );
	end
	
	self.phi = nl.new_vector();
	self.phi:reserve( #self.phi_str_idx )
	for k,v in pairs(self.phi_str_idx) do 
		self.phi:add( tonumber(v) );
	end
	
	
	--tensor3转化为tensor4
	--tensor3的维度为：theta, freq,
	--把tensor3的数据维度转换为tensor4
	local tensor4 = nl.new_eigen_ctensor4(#self.theta_str_idx,#self.phi_str_idx,#self.freq_str_idx,2);
	local listdata = {}
	for kt,vt in pairs(self.theta_str_idx) do
		for kp,vp in pairs(self.phi_str_idx) do
			label = vt..vp;
			listdata[label] = {kt,kp};
			print(label)
		end
	end
	
	for ii=1,#theta do 
		local label = tostring(theta[ii])..tostring(phi[ii]);
		local idx = listdata[label];
		print(label)
		assert( idx~=nil, '数据不完整')
		for kk=1,#self.freq_str_idx do 
			tensor4[{idx[1],idx[2],kk,1}] = tensor3[ {ii,kk,1}]
			tensor4[{idx[1],idx[2],kk,2}] = tensor3[ {ii,kk,2}]
		end 		
	end
	self.data = tensor4;
	
	self.theta_idx = {}
	for kt,vt in pairs(self.theta_str_idx) do
		self.theta_idx[kt]=kt;
	end
	
	self.phi_idx = {}
	for kt,vt in pairs(self.phi_str_idx) do
		self.phi_idx[kt]=kt;
	end

	self.freq_idx = {}
	for kt,vt in pairs(self.freq_str_idx) do
		self.freq_idx[kt]=kt;
	end
	
	self:update_list_to_ui()
end
--===========================================================================--

--===========================================================================--
function FarfieldsPostProcessing:get_data(xAxis,thetas,phis,freqs,fts)
	local fun = function( data,ii,jj,kk,ll )
		return nl.abs( data(ii,jj,kk,1) ) 
	end
	local val = nl.new_vector(#self.theta);
	for ii = 1,#self.theta do 
		val[ii] = fun(self.data,ii,jj,kk,ll);
	end
end
--===========================================================================--

--===========================================================================--
--画单个状态的RCS图
function FarfieldsPostProcessing:add_theta_graph(view,phi,freq,polar)
	local val = nl.new_vector(#self.theta);
	for ii = 1,#self.theta do 
		val[ii] = self.data_post_fun( self.RCS[{ii,phi,freq,polar}] )
	end
	view:addGraph( self.theta, val, self.freq[freq] ..' GHz 俯仰角 '..self.phi[phi] ..'° ' .. self.polars[polar])
end

function FarfieldsPostProcessing:add_theta_curves(freqs,thetas,phis,fts)
	for kp,vp in pairs(phis) do 
		for kf,vf in pairs(freqs) do 
			for kft,vft in pairs (fts) do 
				self:add_theta_graph(self.view,kp,kf,kft);
			end
		end
	end
	self.view:rescaleAxes();
end
--===========================================================================--

function FarfieldsPostProcessing:clear_curves()
	 assert(self.view, "You should creat a viewer first" )
	 assert(self.mw:hasView(self.view)==true,"The viewer is closed!")
	 self.mw:activeView(self.view);
	 self.view:clearGraphs()
	 self.view:rescaleAxes();
end





function FarfieldsPostProcessing:add_freq_curves(freqs,thetas,phis,fts)

	-- print_table(thetas);
	-- print_table(phis);
	-- print_table(fts);
	
	local n = #thetas * #phis * #fts;
	local xx = nl.new_vector(#self.freq_idx);
	local yys ={}
	local lables={}
	for ii=1,n do
	    yys[ii] = nl.new_vector( #self.freq_idx );
	end
	
	jj=1;
	for t,tt in pairs(thetas) do
		for p,pp in pairs(phis) do
			for ft,ftt in pairs(fts) do
				idx = "";
				if #thetas > 1 then idx =  idx .. "Theta[" ..tt .. "] " end
				if #phis > 1 then idx =  idx .. "Phi[" ..pp .. "] " end
				if #fts > 1 then idx =  idx .. "[" ..ftt .. "]" end
				lables[jj] = idx;
				jj = jj+1;
			end
		end
	end

	for f,ff in pairs( self.freq_idx ) do
		xx[f] = tonumber(ff);
		jj=1;
		for t,tt in pairs(thetas) do
			for p,pp in pairs(phis) do
				for ft,ftt in pairs(fts) do
					idx = tt .." ";
					idx = idx .. pp .." ";
					idx = idx .. ftt .." ";
					idx = idx .. ff;
					yys[jj][f] = tonumber( self.listdata[ idx ] );
					jj = jj+1;
				end
			end
		end
	end

	self:init_freq_spectrum_plot();

	for ii=1,n do
	     local gp = self.view:addGraph(xx,yys[ii],lables[ii])	    
	end		
	self.view:rescaleAxes();
end





function FarfieldsPostProcessing:add_phi_curves(freqs,thetas,phis,fts)

	if  self.view then
		local n = #freqs * #thetas * #fts;
		local xx = nl.new_vector(#self.phi_idx);
		local yys ={}
		local lables={}
		for ii=1,n do
		    yys[ii] = nl.new_vector( #self.phi_idx );
		end
		
		jj=1;
		for f,ff in pairs(freqs) do
			for t,tt in pairs(thetas) do
				for ft,ftt in pairs(fts) do
					idx = "";
					if #freqs > 0 then idx =  idx .. "Frequency[" ..ff .. " GHz] " end
					if #thetas > 1 then idx =  idx .. "Theta[" ..tt .. "] " end
					if #fts > 1 then idx =  idx .. "[" ..ftt .. "]" end
					lables[jj] = idx;
					jj = jj+1;
				end
			end
		end

		for p,pp in pairs( self.phi_idx ) do
			xx[p] = tonumber(pp);
			jj=1;
			for f,ff in pairs(freqs) do
				for t,tt in pairs(thetas) do
					for ft,ftt in pairs(fts) do
						idx = tt .." ";
						idx = idx .. pp .." ";
						idx = idx .. ftt .." ";
						idx = idx .. ff;
						local idx1 = self:generate_idx(ff,tt,pp,ftt)

						--print(jj,p, idx,idx1,self.listdata[ idx1 ],self.listdata[ idx ])
						yys[jj][p] = tonumber( self.listdata[ idx ] );
						--print(jj,p,yys[jj][p])
						jj = jj+1;
					end
				end
			end
		end

		self:init_angle_phi_spectrum_plot();

		for ii=1,n do
		     local gp = self.view:addGraph(xx,yys[ii],lables[ii])	    
		end		
		self.view:rescaleAxes();
	end
	
end




function FarfieldsPostProcessing:add_view()
	local gallop = require "QGMainWindow"
	local plot = require "Q2DViewerEx"
	self.mw = gallop.getMainWindow();
	self.view = self.mw:create2DView("View2D");
end

function FarfieldsPostProcessing:select_active_view()
	local gallop = require "QGMainWindow"
	self.mw = gallop.getMainWindow();
	local view = self.mw:activeViewer2DChild();
	assert(self.mw:hasView(view)==true,"The active view is not a 2D viewer!")
	self.view = view;
end

function FarfieldsPostProcessing:set_view(set)
	assert(self.view,"需要创建一个视图或者选择一个视图");
	local script = "return {".. set .."}";
	-- print( script );
	
	local f = load(script)
        local res = f();
	
	
	if res.xAxis ~= nil then
		self.view.xAxis:setProperty( res.xAxis )
	end
     
     	if res.yAxis ~= nil then
		self.view.yAxis:setProperty( res.yAxis )
	end
	
	if res.xAxis2 ~= nil then
		self.view.xAxis2:setProperty( res.xAxis2)
	end
	
	if res.yAxis2 ~= nil then
		self.view.yAxis2:setProperty( res.yAxis2 )
	end
	
	if res.gp1 ~= nil then
		 self.view:graph(1):setProperty( res.gp1 )
		-- print( type( self.view:graph() ) )
		-- print(self.view:graphCount())
	end
	self.view:replot()
end

function FarfieldsPostProcessing:init_freq_spectrum_plot()
	if self.view then
		self.view.xAxis:setProperty( {name="频率 [GHz]"} )
		self.view.yAxis:setProperty( {name="RCS [sm]"} )
		self.view:rescaleAxes();
	end
end
function FarfieldsPostProcessing:init_angle_theta_spectrum_plot()
	if self.view then
		self.view.xAxis:setProperty( {name="角度 θ [°]"} )
		self.view.yAxis:setProperty( {name="RCS [sm]"} )
		self.view:rescaleAxes();
	end
end

function FarfieldsPostProcessing:init_angle_phi_spectrum_plot()
	if self.view then
		self.view.xAxis:setProperty( {name="角度 φ [°]"} )
		self.view.yAxis:setProperty( {name="RCS [sm]"} )
		self.view:rescaleAxes();
	end
end

function FarfieldsPostProcessing:init_plot()
	if self.refView then
		self.refView.xAxis:setProperty( {name="Wavelength [nm]"} )
		self.refView.yAxis:setProperty( {name="Reflection [%]"} )
		self.refView:rescaleAxes();
	end
	 
	if self.tranView then
		self.tranView.xAxis:setProperty( {name="Wavelength [nm]"} )
		self.tranView.yAxis:setProperty( {name="Transmission [%]"} )
		self.tranView:rescaleAxes();	
	end
end

function FarfieldsPostProcessing:init_view_plot(view)
	if self.view then
		view.xAxis:setProperty( {name="Wavelength [nm]"} )
		view.yAxis:setProperty( {name="Reflection [%]"} )
		view:rescaleAxes();
	end
end


return FarfieldsPostProcessing;


